package ultrastarography;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;

public class Song {
	private static final Logger log = LoggerFactory.getLogger(Song.class);
	public static final String PREFIX = "#";
	public static final String SPLIT = ":";
	public static final String[] INFORMATION = { "ALBUM", "ARTIST", "AUTHOR",
			"AUTOR", "BACKGROUND", "BPM", "COVER", "CREATOR", "EDITION",
			"ENCODING", "END", "GAP", "GENRE", "ID", "LANGUAGE", "LENGTH",
			"MADE BY", "MEDLEYENDBEAT", "MEDLEYSTARTBEAT", "MP3", "NOTESGAP",
			"PREVIEWSTART", "RELATIVE", "RESOLUTION", "START", "TITLE",
			"VERSION", "VIDEO", "VIDEOGAP", "YEAR" };
	private File file;
	private String[] data;
	private boolean changed;

	public Song(File inputFile) {
		if (log.isDebugEnabled()) {
			log.debug("Parsing file: '{}'", inputFile.getAbsolutePath());
		}

		changed = false;
		file = inputFile;
		data = new String[INFORMATION.length];
		for (int i = 0; i < data.length; ++i) {
			data[i] = "";
		}

		try {
			FileReader fr = new FileReader(inputFile);
			BufferedReader br = new BufferedReader(fr);
			String line;
			while (!Strings.isNullOrEmpty(line = br.readLine())) {
				if (line.contains(PREFIX)) {
					line = line.replace(PREFIX, "").trim();

					String[] splitLine = line.split(":");
					if (splitLine.length != 2) {
						if (log.isDebugEnabled()) {
							log.debug("Couldn't split line: {}", line);
						}
						continue;
					}

					int dataIndex = Collections.binarySearch(Arrays
							.asList(INFORMATION), splitLine[0].trim()
							.toUpperCase());
					if (log.isDebugEnabled()) {
						log.debug(
								"Line: {} Split[0]: {} Split[1]: {} Index: {}",
								new Object[] { line, splitLine[0],
										splitLine[1], dataIndex });
					}
					data[dataIndex] = splitLine[1].trim();
				} else {
					break;
				}
			}
			br.close();
			fr.close();
		} catch (FileNotFoundException e) {
			if (log.isDebugEnabled()) {
				log.debug("File '{}' not found.", inputFile.getAbsolutePath());
			}
		} catch (IOException e) {
			if (log.isDebugEnabled()) {
				log.debug("IOException '{}'", e.getMessage());
			}
		}
	}

	public void setChanged() {
		changed = true;
	}

	public boolean getChanged() {
		return changed;
	}

	public void saveChangesToFile() {
		try {
			List<String> outputLines = new LinkedList<String>();

			for (int i = 0; i < INFORMATION.length; ++i) {
				if (!Strings.isNullOrEmpty(data[i])) {
					outputLines.add(String.format("%s%s:%s", PREFIX,
							INFORMATION[i], data[i]));
				}
			}

			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			String line;
			while (!Strings.isNullOrEmpty(line = br.readLine())) {
				if (line.contains(PREFIX)) {
					continue;
				} else {
					outputLines.add(line.trim());
				}
			}
			br.close();
			fr.close();

			FileWriter fw = new FileWriter(file);
			BufferedWriter bw = new BufferedWriter(fw);
			PrintWriter pw = new PrintWriter(bw);
			for (String str : outputLines) {
				pw.write(str);
				pw.write("\n");
			}
			pw.close();
			fw.close();
			fw.close();
		} catch (FileNotFoundException e) {
			if (log.isDebugEnabled()) {
				log.debug("File '{}' not found.", file.getAbsolutePath());
			}
		} catch (IOException e) {
			if (log.isDebugEnabled()) {
				log.debug("IOException '{}'", e.getMessage());
			}
		} finally {
			changed = false;
		}
	}

	public String getData(int index) {
		return data[index];
	}

	public void setInformationValue(int index, String value) {
		data[index] = value;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("{");
		for (int i = 0; i < INFORMATION.length; ++i) {
			sb.append("\"").append(INFORMATION[i]).append("\": \"")
					.append(data[i]).append("\"");
			if (i != INFORMATION.length - 1)
				sb.append(", ");
		}
		sb.append("}");

		return sb.toString();
	}
}
